package com.example.landlord.demo.utils.system;

import com.example.landlord.demo.Service.IUserService;
import com.example.landlord.demo.Service.Impl.UserService;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.JsonNodeFactory;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.java_websocket.WebSocket;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Random;
import java.util.Scanner;

//每局的游戏类
public class LandLord extends Game {
//    @Autowired
//    IUserService iUserService;

    public PuckerSystem puckerSystem=new PuckerSystem();   //扑克操纵类

    Player landlord;                                        //地主
    PuckerStep lastPuckerStep = new PuckerStep();           //记录最近一次是哪个玩家出的牌型以及牌值
    int[] lastPokers;   //记录最近一次打出的是什么牌
    boolean flag=false;     //记录是否为开局第一次出牌
    boolean noSend=false;   //是否没有出牌
    volatile int currentIndex=0;     //记录轮到哪个玩家
    volatile int score=0;           //记录最大叫分值
    int processing=0;       //记录游戏进程，0为叫分阶段，1为打牌阶段，2为结束阶段
    volatile ArrayList<ChatMessage> chatMessageArrayList;

    public LandLord(MyWebSocketServer myWebSocketServer){
        super(myWebSocketServer);
        this.gameType = GameType.LANDLORD;
        this.num=3;
    }

    public void setGameStatus(GameStatus gameStatus){
        this.gameStatus = gameStatus;
    }

    @Override
    public void runGame() {
        super.runGame();
        System.out.println("游戏初始化!");
        setGameStatus(GameStatus.STARTED);
        //通知各玩家进入游戏界面
        sendGameStatus();
        //游戏初始化
        init();
    }

    @Override
    public void delGame(){
        ObjectMapper objectMapper = new ObjectMapper();
        ArrayNode arrayNode = objectMapper.createArrayNode();
        ObjectNode result = objectMapper.createObjectNode();
        for(LandLord l : myWebSocketServer.landlordList){
            if(l.id.equals(this.id)){
                myWebSocketServer.landlordList.remove(l);
                l=null;
                break;
            }
        }
        for(LandLord l : myWebSocketServer.landlordList){
            ObjectNode o = objectMapper.createObjectNode();
            o.put("roomName", l.name);
            o.put("created", l.createdPlayer.user.id);
            o.put("num", l.players.size());
            o.put("roomId", l.id);
            arrayNode.add(o);
        }
        result.put("order", 4);
        result.put("list", arrayNode);
        try{
            String json = objectMapper.writeValueAsString(result);
            //广播发送
            Collection<User> userCollection = myWebSocketServer.userCollection.getUsers();
            for(User u : userCollection){
                try{
                    u.webSocket.send(json);
                }catch (Exception e){
                    System.out.println("广播房间列表出现了问题，问题用户:"+u.name);
                    continue;
                }
            }
        }catch (JsonProcessingException e){
            e.printStackTrace();
        }
    }

    //玩家顺序混淆
    public void playerRandom(){
        Random random=new Random();
        //打乱玩家的顺序
        for(int i=0;i<3;i++){
            Player p=players.get(i);
            int r=random.nextInt(3);
            players.set(i, players.get(r));
            players.get(i).index=i;
            players.set(r,p);
            players.get(r).index=r;
        }
    }

    //叫分争地主,true为争地主成功，false为当前没有选出地主
    public boolean speakScore(WebSocketMessage webSocketMessage){
        //开始叫分
        if(processing!=0){
            return false;
        }
        //没有轮到该玩家叫分，直接拒绝消息
        if(!checkIsCurrentPlayer(webSocketMessage)){
            return false;
        }
        Player currentPlayer = players.get(currentIndex);
        if(webSocketMessage.score>this.score){
            this.score= webSocketMessage.score;
            landlord=currentPlayer;
        }
        //直接有人3分，就直接结束叫分，成为地主
        if(score==3){
            //直接进入打牌阶段
            进入打牌阶段();
            return true;
        }else{
            currentIndex++;
            if(currentIndex>2){
                //到了尽头，都没有人叫分，就最后一个人当地主
                if(score==0){
                    //重新洗牌、发牌
//                    init();
                    //通知前端重新获取新游戏
                    this.score= webSocketMessage.score;
                    landlord=currentPlayer;
                    进入打牌阶段();
                    return true;
                }else{
                    //直接进入打牌阶段
                    进入打牌阶段();
                }
            }
        }
        通知叫分情况(webSocketMessage.score, currentPlayer.index);
        return true;
    }

    void 进入打牌阶段(){
        processing=1;
        currentIndex=landlord.index;
        landlord.times+=2;
        //借用叫分函数，来向玩家通知当前的状态
        通知叫分情况(0,0);
    }

    void 通知叫分情况(int score, int index){
        ObjectMapper objectMapper=new ObjectMapper();
        ObjectNode node = objectMapper.createObjectNode();
        try{
            node.put("order",3);
            node.put("mode",2);
            node.put("status",processing==1?1:0);
            node.put("score",score);
            node.put("index",index);
            node.put("nextIndex",currentIndex);
            node.put("landlord",processing==1?landlord.index:-1);
            for(Player p:players){
                noticeTimes(p);
                String json=objectMapper.writeValueAsString(node);
                p.user.webSocket.send(json);
            }
        }catch (JsonProcessingException e){
            e.printStackTrace();
        }
    }

    //获取当前游戏的进程
    public void getGameProcessing(WebSocketMessage webSocketMessage){
        if(getPlayerBySocket(webSocketMessage.webSocket)==null){
            return;
        }
        ObjectMapper objectMapper = new ObjectMapper();
        ObjectNode node = objectMapper.createObjectNode();
        node.put("order",7);
        node.put("processing", processing);
        node.put("currentIndex",currentIndex);
        if(processing!=0){
            node.put("landlord", landlord.index);
            ArrayNode arrayNode = objectMapper.createArrayNode();
            for (int id : lastPokers) {
                ObjectNode objectNode = objectMapper.createObjectNode();
                objectNode.put("name", puckerSystem.pukerList[id].pName);
                objectNode.put("value", puckerSystem.pukerList[id].value);
                objectNode.put("id", puckerSystem.pukerList[id].id);
                objectNode.put("color", puckerSystem.pukerList[id].color);
                objectNode.put("sended", puckerSystem.pukerList[id].status == PuckerStatus.NOTSEND ? false : true);
                arrayNode.add(objectNode);
            }
            node.put("lastPoker",arrayNode);//上一次打出的牌
            node.put("lastPlayer",lastPuckerStep.player==null?-1:lastPuckerStep.player.index);//哪个玩家打出的牌
        }
        sendMessage(webSocketMessage.webSocket, node);
    }

    void sendMessage(WebSocket webSocket,ObjectNode objectNode){
        ObjectMapper objectMapper = new ObjectMapper();
        try{
            webSocket.send(objectMapper.writeValueAsString(objectNode));
        }catch (JsonProcessingException e){}
    }
    //判断该信息发送者是否为本局的玩家，非本局玩家不允许进行操作

    //显示每个玩家手里的牌
    public void showEveryonePucker(){
        for(int i=0;i<3;i++){
            System.out.println("----------\""+players.get(i).user.name+"\"的手牌----------");
            for(int j=0;j<17;j++){
                Puker p = puckerSystem.pukerList[players.get(i).index*17+j];
                System.out.println(p.toString());
            }
        }
    }

    //显示3张底牌
    public void showDiPai(){
        System.out.println("----------底牌----------");
        System.out.println(puckerSystem.pukerList[puckerSystem.pukerList.length-3].toString());
        System.out.println(puckerSystem.pukerList[puckerSystem.pukerList.length-2].toString());
        System.out.println(puckerSystem.pukerList[puckerSystem.pukerList.length-1].toString());
    }

    //游戏初始化
    public void init(){
            playerRandom();                         //玩家顺序随机打乱
            puckerSystem=new PuckerSystem();
            puckerSystem.shuffle();                 //洗牌发牌
            processing=0;
            landlord=new Player();
            lastPokers=new int[0];
            noSend=false;
            score=0;
            currentIndex=0;
            processing=0;
            lastPuckerStep=new PuckerStep();
            flag=false;
            chatMessageArrayList=new ArrayList<>();
    }

    boolean checkIsCurrentPlayer(WebSocketMessage webSocketMessage){
        Player currentPlayer = players.get(currentIndex),MessagePlayer=null;
        //验证此回合是否应该由发消息的玩家出牌
        for(Player p : players){
            if(p.user.webSocket==webSocketMessage.webSocket){
                MessagePlayer=p;
                break;
            }
        }
        if(MessagePlayer!=currentPlayer){
            //不是该回合的玩家操作消息直接屏蔽
            return false;
        }
        return true;
    }

    //通知倍数
    void noticeTimes(Player p){
        ObjectMapper objectMapper = new ObjectMapper();
        ObjectNode objectNode = objectMapper.createObjectNode();
        objectNode.put("order",12);
        objectNode.put("times",p.times==0?1:p.times);
        objectNode.put("money",p.money);
        System.out.println("sended");
        sendMessage(p.user.webSocket, objectNode);
    }

    //计算玩家倍数
    void calcTimes(Player p, DefinePucker definePucker){
        if(p==null){return;}
        switch (definePucker){
            case BOMB:
            case CONTINUEBOMB:
                p.times+=2;
                break;
            case ROCKET:
                p.times+=4;
                break;
        }
    }

    @Override
    public boolean gameDoing(WebSocketMessage webSocketMessage) {
        super.gameDoing(webSocketMessage);

        //游戏正体代码
        //如果游戏并没有进入打牌阶段，就拒绝此消息
        if(processing!=1){
            return false;
        }
        //获取当前应该出牌的玩家
        if(!checkIsCurrentPlayer(webSocketMessage)){
            return false;
        }
        int[] sendingPuckers = webSocketMessage.idList;   //当前出牌的id序列
        Player bufPlayer = players.get(currentIndex);
        if(lastPuckerStep.player==bufPlayer&&flag){
            flag=false;
        }
        //检查打出的牌是否为该玩家的牌
        if(!checkOutId(sendingPuckers,players.get(currentIndex))){
            return false;
        }
        noSend=sendingPuckers.length==0;
        //如果玩家选择不出牌，或者它断线了
        if(sendingPuckers.length==0){
            //指向下一个玩家，如果是末尾则回到第一个玩家
            currentIndex++;
            if(currentIndex>2){
                currentIndex=0;
            }
            return true;
        }
        PuckerStep puckerStep = puckerSystem.verification(sendingPuckers);
        puckerStep.player=bufPlayer;
        puckerStep.length = sendingPuckers.length;
        //判断是否为非法牌型
        if(puckerStep.definePucker==DefinePucker.ILLEGAL) {
            return false;
        }
        if (!flag) {
//            System.out.println("flag:"+flag);
            //如果是开局第一次出的牌，就不用再比较牌型与牌值，直接出牌
            flag = true;  //标志当前游戏第一个玩家已经出了牌
            recordPuckerStep(puckerStep, sendingPuckers);
        }
        //检查牌型与上一次的是否一致以及牌值是否比上一次的大
        else {
            if(puckerStep.definePucker == DefinePucker.ROCKET){
                System.out.println("出了火箭,直接过");
                recordPuckerStep(puckerStep, sendingPuckers);
            }else{
//                System.out.println("判断当中:"+(puckerStep.definePucker==DefinePucker.BOMB ?true:puckerStep.definePucker == lastPuckerStep.definePucker));
//                System.out.println("判断值大小:"+(puckerStep.puckerValue > lastPuckerStep.puckerValue));
//                System.out.println("总体判断:"+((puckerStep.definePucker==DefinePucker.BOMB ?true:puckerStep.definePucker == lastPuckerStep.definePucker) && puckerStep.puckerValue > lastPuckerStep.puckerValue));
                if(lastPuckerStep.definePucker == DefinePucker.BOMB && puckerStep.definePucker==DefinePucker.BOMB && puckerStep.puckerValue > lastPuckerStep.puckerValue){
                    recordPuckerStep(puckerStep, sendingPuckers);
                }else if(puckerStep.definePucker==DefinePucker.BOMB){
                    recordPuckerStep(puckerStep, sendingPuckers);
                }else if(puckerStep.definePucker == lastPuckerStep.definePucker && puckerStep.length == lastPuckerStep.length && puckerStep.puckerValue > lastPuckerStep.puckerValue){
//                System.out.println("上一次出的牌型:"+lastPuckerStep.definePucker+",牌值:"+lastPuckerStep.puckerValue+",是否第一次出牌:"+flag);
//                System.out.println("现在出的牌型:"+puckerStep.definePucker+",牌值:"+puckerStep.puckerValue+",是否第一次出牌:"+flag);
                    recordPuckerStep(puckerStep, sendingPuckers);
                }else{
                    System.out.println("牌型判断:"+(puckerStep.definePucker == lastPuckerStep.definePucker));
                    System.out.println("长度判断:"+(puckerStep.length == lastPuckerStep.length)+","+puckerStep.length+":"+lastPuckerStep.length);
                    System.out.println("牌值判断:"+(puckerStep.puckerValue > lastPuckerStep.puckerValue));
                    System.out.println("总体判断:"+(puckerStep.definePucker == lastPuckerStep.definePucker && puckerStep.length == lastPuckerStep.length && puckerStep.puckerValue > lastPuckerStep.puckerValue));
                    return false;
                }
            }
        }
        Player currentPlayer = players.get(currentIndex);
        if(sendingPuckers.length!=0){
            //该玩家出牌
            lastPuckerStep.player=currentPlayer;
            puckerSystem.sendPucker(sendingPuckers,currentPlayer);
        }
        //检查该玩家的牌是否出完，出完则胜利
        if(puckerSystem.countNotSend(currentPlayer)==0){
            System.out.println("游戏胜利");
            victoryNotice(currentPlayer);
        }
        //指向下一个玩家，如果是末尾则回到第一个玩家
        currentIndex++;
        if(currentIndex>2){
            currentIndex=0;
        }
        return true;
    }

    //游戏胜利通知
    void victoryNotice(Player p){
        //参数p是胜利者玩家
        //游戏状态设置为结束状态
        processing=2;
        gameStatus=GameStatus.WAITING;
        ObjectMapper objectMapper = new ObjectMapper();
        ObjectNode objectNode = objectMapper.createObjectNode();
        objectNode.put("order",11);
        boolean a = p==landlord;
        objectNode.put("landlord", a);
        //将所有玩家的状态改为未准备
        for(Player player:players){
            player.ready=false;
            player.score=0;
            player.started=false;
            int fushu=p==player?1:-1;
//            iUserService.addScore(player.user.id,calcScore(player)*fushu);
            player.money=20;
            player.times=0;
            player.read=0;
            sendMessage(player.user.webSocket,objectNode);
        }
    }

    //游戏结束后计算玩家的分数
    int calcScore(Player p){
        if(p.times==0){p.times=1;}
        return p.times*p.money;
    }

    @Override
    public void playerExit(Player p) {
        super.playerExit(p);
//        if(currentIndex==p.index){
//            System.out.println("该玩家退出了游戏，让下一名玩家继续");
//            currentIndex++;
//            if(currentIndex>2){
//                currentIndex=0;
//            }
//        }
        //通知状态
    }

    //查询下一个由谁来叫分
    public void getScoreByPlayer(WebSocketMessage webSocketMessage){
        ObjectMapper objectMapper=new ObjectMapper();
        ObjectNode node = objectMapper.createObjectNode();
        node.put("order",8);
        node.put("nextIndex",currentIndex);
        sendMessage(webSocketMessage.webSocket,node);
    }

    //向请求牌的玩家发送他的牌列表
    public void getPuckerByPlayer(WebSocket webSocket){
        Player player = getPlayerBySocket(webSocket);
        if(player==null){
            return;
        }
        noticeTimes(player);
        ObjectMapper objectMapper = new ObjectMapper();
        ObjectNode node = objectMapper.createObjectNode();
        node.put("order",3);
        node.put("mode",0);
        Player bufPlayer=getPlayerBySocket(webSocket);
        node.put("start",bufPlayer.started);
        bufPlayer.started=true;
        ArrayNode dipai=objectMapper.createArrayNode();
        for(int j=puckerSystem.pukerList.length-1;j>puckerSystem.pukerList.length-4;j--){
            ObjectNode poker= objectMapper.createObjectNode();
            poker.put("name",puckerSystem.pukerList[j].pName);
            poker.put("value",puckerSystem.pukerList[j].value);
            poker.put("id",puckerSystem.pukerList[j].id);
            poker.put("color",puckerSystem.pukerList[j].color);
            poker.put("sended",puckerSystem.pukerList[j].status==PuckerStatus.NOTSEND?false:true);
            dipai.add(poker);
        }
        ArrayNode puckerList = objectMapper.createArrayNode();
        for(int j=player.index*17;j<player.index*17+17;j++){
            ObjectNode poker= objectMapper.createObjectNode();
            poker.put("name",puckerSystem.pukerList[j].pName);
            poker.put("value",puckerSystem.pukerList[j].value);
            poker.put("id",puckerSystem.pukerList[j].id);
            poker.put("color",puckerSystem.pukerList[j].color);
            poker.put("sended",puckerSystem.pukerList[j].status==PuckerStatus.NOTSEND?false:true);
            puckerList.add(poker);
        }
        ArrayNode playersNode = objectMapper.createArrayNode();
        for(int j=0;j<players.size();j++){
            ObjectNode poker= objectMapper.createObjectNode();
            poker.put("name",players.get(j).user.name);
            poker.put("picture",players.get(j).user.picture);
            poker.put("index",players.get(j).index);
            poker.put("pokerNum",puckerSystem.countNotSend(players.get(j)));
            playersNode.add(poker);
        }
        node.put("dipai", dipai);
        node.put("puckerList", puckerList);
        node.put("players",playersNode);
        sendMessage(webSocket,node);
    }

    //将这次游戏步奏记录到最近一次游戏步奏里
    public void recordPuckerStep(PuckerStep p, int[] sendPoker){
        lastPuckerStep.definePucker=p.definePucker;
        lastPuckerStep.puckerValue=p.puckerValue;
        lastPuckerStep.player=p.player;
        lastPuckerStep.length = sendPoker.length;
        if(sendPoker!=null){lastPokers=sendPoker;}
        flag=true;
        calcTimes(lastPuckerStep.player,lastPuckerStep.definePucker);
    }

    //判断欲出的牌id是否合法
    public boolean checkOutId(int[] a, Player p){
        for(int j=0;j<a.length;j++){
            if(a[j]>53){
                return false;
            }
            //检查是否为玩家手中的牌，且状态不为已打出牌状态
            boolean isPlayerPucker=false;
            for(int k=p.index*17;k<p.index*17+17;k++){
                if(puckerSystem.pukerList[k].id==a[j]&puckerSystem.pukerList[k].getStatus()!=PuckerStatus.SENDED){
                    isPlayerPucker=true;
                    break;
                }
            }
            if(!isPlayerPucker){
                //如果在玩家手牌里没有找到对应的17张牌，那就查看玩家是否为地主，如果是地主，则在3张底牌中寻找一遍
                if(p==landlord&(a[j]==puckerSystem.pukerList[53].id|a[j]==puckerSystem.pukerList[52].id|a[j]==puckerSystem.pukerList[51].id)){
                    break;
                }
                return false;
            }
        }
        return true;
    }

    synchronized public void appendChatMessage(WebSocketMessage webSocketMessage){
        Player player=getPlayerBySocket(webSocketMessage.webSocket);
        LocalTime localTime = LocalTime.now();
        ChatMessage chatMessage = new ChatMessage(localTime.getHour()+":"+localTime.getMinute()+":"+localTime.getSecond(),player.index,webSocketMessage.content);
        chatMessageArrayList.add(chatMessage);
        //通知所有玩家的更新
        for(Player p : players){
            getChatMessage(p.user.webSocket);
        }
    }

    void getChatMessage(WebSocket webSocket){
        Player player=getPlayerBySocket(webSocket);
        ObjectMapper objectMapper = new ObjectMapper();
        ObjectNode objectNode = objectMapper.createObjectNode();
        ArrayNode messages = objectMapper.createArrayNode();
        for(ChatMessage chatMessage : chatMessageArrayList){
            ObjectNode message = objectMapper.createObjectNode();
            message.put("time",chatMessage.time);
            message.put("index",chatMessage.index);
            message.put("content",chatMessage.content);
            messages.add(message);
        }
        objectNode.put("order",13);
        objectNode.put("messages",messages);
        objectNode.put("read",player.read);
        sendMessage(webSocket,objectNode);
    }

    //设置玩家已读
    void setPlayerRead(WebSocketMessage webSocketMessage){
        Player player = getPlayerBySocket(webSocketMessage.webSocket);
        player.read= chatMessageArrayList.size();
        getChatMessage(webSocketMessage.webSocket);
    }
}
